/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package chat.sound;

import java.util.Collection;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.TargetDataLine;

/**
 *
 * @author salm
 */
public class SoundRecorder extends Thread
{
    public static final int BUFFER_SIZE = 4096;
    public static final int DEFAULT_SLEEPTIME = 0x0;
    
    private TargetDataLine targetDataLine;
    private AudioFormat audioFormat;
    private byte tempBuffer[] = new byte[BUFFER_SIZE];
    private int sleepTime = DEFAULT_SLEEPTIME;
    private Collection<SoundRecorderListener> listeners = new LinkedList();
    private boolean isRunning = false;
    
    public SoundRecorder()
    {
        this.initAudioFormat();
        this.initDataLine();
    }
    
    private void initDataLine() {
        try {
            Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
            System.out.println("Available mixers:");
            for (int cnt = 0; cnt < mixerInfo.length; cnt++) {
                System.out.println(mixerInfo[cnt].getName());
            }

            DataLine.Info dataLineInfo = new DataLine.Info(
                    TargetDataLine.class, audioFormat);

            Mixer mixer = AudioSystem.getMixer(mixerInfo[3]);
            targetDataLine = (TargetDataLine) mixer.getLine(dataLineInfo);
        } catch (Exception e) {
            System.out.println(e);
            System.exit(0);
        }
    }

    private void initAudioFormat() {
        float sampleRate = 8000.0F;
        int sampleSizeInBits = 16;
        int channels = 1;
        boolean signed = true;
        boolean bigEndian = false;
        this.audioFormat = new AudioFormat(
                sampleRate,
                sampleSizeInBits,
                channels,
                signed,
                bigEndian);
    }
    
    @Override
    public void start()
    {
        try {
            targetDataLine.open(audioFormat);
            targetDataLine.start();
            this.isRunning = true;
            super.start();
        } catch (LineUnavailableException ex) {
            Logger.getLogger(SoundRecorder.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void terminal()
    {
        targetDataLine.stop();
        targetDataLine.close();
        this.isRunning = false;
    }
    
    @Override
    public void run()
    {
        try {
            while (this.isRunning) {
                int cnt = targetDataLine.read(tempBuffer, 0, tempBuffer.length);
                if (cnt > 0)    // has data
                {
                    System.out.println("Recorded: "+ cnt);
                    for (SoundRecorderListener listener : this.listeners)
                    {
                        listener.onRecordData(tempBuffer, cnt);
                    }
                }

                if (this.getSleepTime() > 0)
                {
                    Thread.sleep(this.getSleepTime());
                }
            }
        } catch (InterruptedException ex) {
            this.terminal();
        }
    }

    /**
     * @return the sleepTime
     */
    public int getSleepTime() {
        return sleepTime;
    }

    /**
     * @param sleepTime the sleepTime to set
     */
    public void setSleepTime(int sleepTime) {
        this.sleepTime = sleepTime;
    }

    /**
     * @return the listeners
     */
    public Collection<SoundRecorderListener> getListeners() {
        return listeners;
    }

    /**
     * @return the isRunning
     */
    public boolean isIsRunning() {
        return isRunning;
    }

    /**
     * @param isRunning the isRunning to set
     */
    public void setIsRunning(boolean isRunning) {
        this.isRunning = isRunning;
    }
}